package com.yzy.util.algorithm;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.yzy.exception.GlobalExceptionMessage;
import com.yzy.exception.VisionException;
import com.yzy.properties.GlobalProperties;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Component
public class JWTUtils {

    private static com.yzy.properties.GlobalProperties globalProperties;

    public JWTUtils(GlobalProperties globalProperties) {
        JWTUtils.globalProperties = globalProperties;
    }

    public static String sign(String id) {
        try {
            // 获取时间
            Date date = new Date(System.currentTimeMillis() + globalProperties.getTokenExpireTime());
            // 私钥以及加密算法
            Algorithm algorithm = Algorithm.HMAC256(globalProperties.getTokenSecret());
            // 设置头部信息
            Map<String, Object> header = new HashMap<>(2);
            header.put("typ", "JWT");
            header.put("alg", "HS256");

            // 将header，algorithm，date结合生成token
            String token = JWT.create()
                    .withHeader(header)
                    .withClaim("id", id)
                    .withExpiresAt(date)
                    .sign(algorithm);
            return globalProperties.getTokenPrefix() + token;
        } catch (Exception e) {
            throw new VisionException(HttpStatus.EXPECTATION_FAILED, GlobalExceptionMessage.INTERNAL_SERVER_HANDLE_FAILED);
        }
    }

    public static void verify(String token) throws VisionException {
        try {
            token = token.replace(globalProperties.getTokenPrefix(), "");
            Algorithm algorithm = Algorithm.HMAC256(globalProperties.getTokenSecret());
            JWTVerifier verifier = JWT.require(algorithm).build();
            verifier.verify(token);
        } catch (Exception e) {
            throw new VisionException(HttpStatus.UNAUTHORIZED, GlobalExceptionMessage.TOKEN_INVALID_ON_REQUEST_HEADER);
        }
    }

    public static String getIdFromRequest(HttpServletRequest request) {
        String token = getTokenFromRequest(request);
        return getIdFromToken(token);
    }

    public static String getIdFromToken(String token) {
        verify(token);

        try {
            DecodedJWT decode = JWT.decode(token);

            return decode.getClaim("id").asString();
        } catch (Exception e) {
            throw new VisionException(HttpStatus.UNAUTHORIZED, GlobalExceptionMessage.TOKEN_INVALID_ON_REQUEST_HEADER);
        }
    }

    public static String getIdFromBearerToken(String bearerToken) {
        String token = bearerToken.replace(globalProperties.getTokenPrefix(), "");
        return getIdFromToken(token);
    }

    private static String getTokenFromRequest(HttpServletRequest request) {
        String token = request.getHeader(globalProperties.getTokenHeader());
        if (StringUtils.isBlank(token)) {
            throw new VisionException(HttpStatus.UNAUTHORIZED, GlobalExceptionMessage.TOKEN_INVALID_ON_REQUEST_HEADER);
        }
        token = token.replace(globalProperties.getTokenPrefix(), "");
        return token;
    }
}
